home *** CD-ROM | disk | FTP | other *** search
/ World of Video / World of Video.iso / gfxprograms / 3dprograms / t3dlib / source / readtddd.c < prev    next >
C/C++ Source or Header  |  1995-02-13  |  41KB  |  1,434 lines

  1. /* ReadTDDD.c - read a TDDD (Three Dimension Data Decription) file
  2.  *            - written by Glenn M. Lewis - 9/4/91
  3.  */
  4.  
  5. static char rcs_id[] = "$Id: readtddd.c,v 1.31 1993/12/11 22:22:19 glewis Exp $";
  6.  
  7. #include <stdio.h>
  8. #include <ctype.h>
  9. #include <math.h>
  10. #include "t3dlib.h"
  11. #ifdef __STDC__
  12. #include <stdlib.h>
  13. #include <strings.h>
  14. #include "readtddd_protos.h"
  15. #endif
  16. #define MAXLINE 132
  17. #ifndef PI
  18. #define PI (3.14159265)
  19. #endif
  20.  
  21. int verbose_flag=0;
  22.  
  23. static void process_DESC();
  24. static OBJECT *process_EXTR();
  25. static void process_INFO();
  26. static void process_OBJ();
  27. void insert_into_sorted_list();
  28.  
  29. /* Here are a few necessary utilities */
  30.  
  31. static void get_name(name, size, world)
  32. register char  *name;
  33. register int size;
  34. WORLD *world;
  35. {
  36.     while (size--) *name++ = fgetc(world->inp);
  37.     *name = '\0';
  38. }
  39.  
  40. static BYTE get_BYTE(world)
  41. WORLD *world;
  42. {
  43.     return((BYTE)fgetc(world->inp));
  44. }
  45.  
  46. static UBYTE get_UBYTE(world)
  47. WORLD *world;
  48. {
  49.     return((UBYTE)fgetc(world->inp));
  50. }
  51.  
  52. static WORD get_WORD(world)
  53. WORLD *world;
  54. {
  55.     WORD tmp = (WORD)get_UBYTE(world)<<8;
  56.     return((WORD)(tmp|get_UBYTE(world)));
  57. }
  58.  
  59. static UWORD get_UWORD(world)
  60. WORLD *world;
  61. {
  62.     UWORD tmp = (UWORD)get_UBYTE(world)<<8;
  63.     return((UWORD)(tmp|get_UBYTE(world)));
  64. }
  65.  
  66. static ULONG get_ULONG(world)
  67. WORLD *world;
  68. {
  69.     ULONG tmp = (ULONG)get_UWORD(world)<<16;
  70.     return(tmp|get_UWORD(world));
  71. }
  72.  
  73. static double get_FRACT(world)    /* This sets the precision to 10^(-3) */
  74. WORLD *world;
  75. {
  76.     register double whole, fract;
  77.  
  78.     whole =  (double)get_WORD(world);
  79.     fract = ((double)get_UWORD(world))/(double)65536.0;
  80.     return((double)(whole+fract));
  81. }
  82.  
  83. static void stuff_XYZ(st, world)
  84. XYZ_st *st;
  85. WORLD *world;
  86. {
  87.     st->x = get_FRACT(world);
  88.     st->y = get_FRACT(world);
  89.     st->z = get_FRACT(world);
  90. }
  91.  
  92. static void stuff_RGB(st, world)
  93. RGB_st *st;
  94. WORLD *world;
  95. {
  96.     get_UBYTE(world);    /* pad byte */
  97.     st->r = get_UBYTE(world);
  98.     st->g = get_UBYTE(world);
  99.     st->b = get_UBYTE(world);
  100. }
  101.  
  102. static void output_warning(world, area, name, size)
  103. WORLD *world;
  104. char *area, *name;
  105. ULONG size;
  106. {
  107.     ULONG i;
  108.     int j;
  109.     unsigned char tmpstr[20];
  110.  
  111.     fprintf(stderr, "WARNING: Unknown %ssub-chunk: '%s', size %lu...\n",
  112.         area, name, size);
  113.     for (i=0; i<size; i+=16) {
  114.         fprintf(stderr, "%04lx:", i);
  115.         for (j=0; j<16 && i+j<size; j++)
  116.             fprintf(stderr, " %02x", tmpstr[j] = (fgetc(world->inp)&0xff));
  117.         while (j++ < 16) fputs("   ", stderr);
  118.         fputs("    ", stderr);
  119.         /* Print out the ASCII equivalent */
  120.         for (j=0; j<16 && i+j<size; j++) {
  121.             tmpstr[j] &= 0x7F;   /* Strip off upper bit */
  122.             if (isprint(tmpstr[j]))
  123.                 fputc(tmpstr[j], stderr);
  124.             else fputc('.', stderr);
  125.         }
  126.         fputs("\n", stderr);
  127.     }
  128. }
  129.  
  130. /********************/
  131. /* The MAIN section */
  132. /********************/
  133.  
  134. int already_read_header = 0;
  135. unsigned char header_storage[13];
  136.  
  137. WORLD *read_World(file)
  138. FILE *file;
  139. {
  140.     int i;
  141.     for (i=0; i<4; i++) header_storage[i] = fgetc(file);
  142.     already_read_header = 4;
  143.     if (strncmp(header_storage, "FORM", 4)==0) {
  144.         while (i<12) header_storage[i++] = fgetc(file);
  145.         already_read_header = 12;
  146.         if (strncmp(&header_storage[8], "TDDD", 4)==0) return(read_TDDD(file));
  147. #if 0
  148.         if (strncmp(&header_storage[8], "LWOB", 4)==0) return(read_LWOB(file));
  149. #endif
  150.         if (strncmp(&header_storage[8], "ISTG", 4)==0) return(read_ISTG(file));
  151.         /* BAD IFF */
  152.         header_storage[12] = 0;
  153.         fprintf(stderr, "ERROR! Unknown FORM: '%s'\n", &header_storage[8]);
  154.         return(0);
  155.     } else {
  156.         return(read_TTDDD(file));
  157.     }
  158. }
  159.  
  160. WORLD *read_TDDD(file)
  161. FILE *file;
  162. {
  163.     register ULONG i, len, size;
  164.     WORLD *world;
  165.     char name[5];
  166.  
  167.     if (!file) return(0L);    /* File not open */
  168.  
  169.     if (!(world = (WORLD*)malloc(sizeof(WORLD)))) { OUT_MEM("WORLD"); }
  170.     bzero((char*)world, sizeof(WORLD));
  171.     world->inp = file;
  172.  
  173.     if (!already_read_header) {
  174.         /* Parse the IFF TDDD file */
  175.         get_name(name, 4, world);
  176.         if (strcmp(name, "FORM") != 0) {
  177.             fprintf(stderr, "ERROR: Input is not an IFF file.\n"); exit(-1); }
  178.         if (!(len = get_ULONG(world))) {
  179.             fprintf(stderr, "ERROR: Bad FORM length in IFF file.\n"); exit(-1); }
  180.         get_name(name, 4, world);
  181.         if (strcmp(name, "TDDD") != 0) {
  182.             fprintf(stderr, "ERROR: IFF file is not a TDDD file.\n"); exit(-1); }
  183.     } else {
  184.         len =    (header_storage[4]<<24) | (header_storage[5]<<16) |
  185.                 (header_storage[6]<< 8) | (header_storage[7]    );
  186.         already_read_header = 0;
  187.     }
  188.     len -= 4;
  189.  
  190. /* Here is the main loop: */
  191.     while (len>0) {
  192.         get_name(name, 4, world);
  193.         size = get_ULONG(world);
  194.         len -= 8;
  195.         if (strcmp(name, "INFO")==0) process_INFO(size, world);
  196.         else
  197.         if (strcmp(name, "OBJ ")==0) process_OBJ(size, world);
  198.         else {
  199.             if (verbose_flag) output_warning(world, "", name, size);
  200.             else {
  201.                 for (i=size; i--; ) fgetc(world->inp);    /* Skip this section */
  202.             }
  203.         }
  204.         if (size&1) { fgetc(world->inp); len--; }    /* Skip odd byte */
  205.         len -= size;
  206.     }
  207.  
  208. /* All done. */
  209.     return(world);
  210. }
  211.  
  212. static void process_INFO(len, world)
  213. register ULONG len;
  214. WORLD *world;
  215. {
  216.     register INFO *info;
  217.     register ULONG i, size;
  218.     char name[5];
  219.  
  220.     if (world->info) {
  221.         fputs("ERROR: More than one INFO chunk!\n", stderr); exit(-1); }
  222.     if (!(info = world->info = (INFO*)malloc(sizeof(INFO)))) { OUT_MEM("INFO"); }
  223.     bzero((char*)world->info, sizeof(INFO));
  224.  
  225.     if (verbose_flag>1) fprintf(stderr, "INFO chunk.\n");
  226.     while (len>0) {
  227.         get_name(name, 4, world);
  228.         size = get_ULONG(world);
  229.         len -= 8;
  230.         if (verbose_flag>1) fprintf(stderr, "%s chunk.\n", name);
  231.         if (strcmp(name, "BRSH")==0) {
  232.             i = get_UWORD(world);
  233.             if (i<0 || i>7) { i=0; fputs("BRSH error.\n", stderr); }
  234.             get_name(info->brsh[i], 80, world);
  235.         } else
  236.         if (strcmp(name, "STNC")==0) {
  237.             i = get_UWORD(world);
  238.             if (i<0 || i>7) { i=0; fputs("STNC error.\n", stderr); }
  239.             get_name(info->stnc[i], 80, world);
  240.         } else
  241.         if (strcmp(name, "TXTR")==0) {
  242.             i = get_UWORD(world);
  243.             if (i<0 || i>7) { i=0; fputs("TXTR error.\n", stderr); }
  244.             get_name(info->txtr[i], 80, world);
  245.         } else
  246.         if (strcmp(name, "OBSV")==0) {
  247.             if (!info->obsv) info->obsv=(OBSV*)malloc(sizeof(OBSV));
  248.             if (!info->obsv) { OUT_MEM("OBSV"); }
  249.             stuff_XYZ(&info->obsv->came, world);
  250.             stuff_XYZ(&info->obsv->rota, world);
  251.             info->obsv->foca = get_FRACT(world);
  252.         } else
  253.         if (strcmp(name, "OTRK")==0) {
  254.             get_name(info->otrk, 18, world);
  255.         } else
  256.         if (strcmp(name, "OSTR")==0) {
  257.             if (!info->ostr) info->ostr=(STRY*)malloc(sizeof(STRY));
  258.             if (!info->ostr) { OUT_MEM("OSTR"); }
  259.             get_name(info->ostr->path, 18, world);
  260.             stuff_XYZ(&info->ostr->tran, world);
  261.             stuff_XYZ(&info->ostr->rota, world);
  262.             stuff_XYZ(&info->ostr->scal, world);
  263.             info->ostr->info = get_UWORD(world);
  264.         } else
  265.         if (strcmp(name, "FADE")==0) {
  266.             if (!info->fade) info->fade=(FADE*)malloc(sizeof(FADE));
  267.             if (!info->fade) { OUT_MEM("FADE"); }
  268.             info->fade->at = get_FRACT(world);
  269.             info->fade->by = get_FRACT(world);
  270.             stuff_RGB(&info->fade->to, world);
  271.         } else
  272.         if (strcmp(name, "SKYC")==0) {
  273.             if (!info->skyc) info->skyc=(SKYC*)malloc(sizeof(SKYC));
  274.             if (!info->skyc) { OUT_MEM("SKYC"); }
  275.             stuff_RGB(&info->skyc->hori, world);
  276.             stuff_RGB(&info->skyc->zeni, world);
  277.         } else
  278.         if (strcmp(name, "AMBI")==0) {
  279.             if (!info->ambi) info->ambi=(RGB_st*)malloc(sizeof(RGB_st));
  280.             if (!info->ambi) { OUT_MEM("AMBI"); }
  281.             stuff_RGB(info->ambi, world);
  282.         } else
  283.         if (strcmp(name, "GLB0")==0) {
  284.             if (!info->glb0) info->glb0=(BYTE*)malloc(8*sizeof(BYTE));
  285.             if (!info->glb0) { OUT_MEM("GLB0"); }
  286.             for (i=0; i<8; i++)
  287.                 info->glb0[i] = get_UBYTE(world);
  288.         } else {
  289.             if (verbose_flag) output_warning(world, "INFO ", name, size);
  290.             else {
  291.                 for (i=size; i--; ) fgetc(world->inp);    /* Skip this section */
  292.             }
  293.         }
  294.         if (size&1) { fgetc(world->inp); len--; }    /* Skip odd byte */
  295.         len -= size;
  296.     }
  297. }
  298.  
  299. static void process_OBJ(len, world)
  300. register ULONG len;
  301. WORLD *world;
  302. {
  303.     register ULONG i, size;
  304.     register OBJECT *p;
  305.     char name[5];
  306.     int depth=0;
  307.  
  308.     if (verbose_flag>1) fprintf(stderr, "OBJ chunk.\n");
  309.     while (len>0) {
  310.         get_name(name, 4, world);
  311.         size = get_ULONG(world);
  312.         len -= 8;
  313.         if (verbose_flag>1) fprintf(stderr, "%s chunk.\n", name);
  314.         if (strcmp(name, "EXTR")==0) {
  315.             p = process_EXTR(size, create_object(), world);
  316.             if (world->curobj) {
  317.                 world->curobj->next = p;
  318.                 p->parent = world->curobj->parent;
  319.             } else {
  320.                 world->object = p;
  321.                 p->parent = 0;
  322.             }
  323.             world->curobj = p;
  324.         } else if (strcmp(name, "DESC")==0) {
  325.             p = create_object();
  326.             if (world->num_DESC > world->num_TOBJ+depth) {  /* This is a child */
  327.                 depth++;    /* Down one in the hierarchy */
  328.                 world->curobj->child = p;
  329.                 p->parent = world->curobj;
  330.             } else {
  331.                 if (world->curobj) {
  332.                     world->curobj->next = p;
  333.                     p->parent = world->curobj->parent;
  334.                 } else {
  335.                     world->object = p;
  336.                     p->parent = 0;
  337.                 }
  338.             }
  339.             world->curobj = p;
  340.             process_DESC(size, &p->desc, world);
  341.         } else if (strcmp(name, "TOBJ")==0) {
  342.             world->num_TOBJ++;
  343.             if (world->num_TOBJ > world->num_DESC) {
  344.                 fprintf(stderr, "Warning: TOBJ without DESC.  Ignored.\n");
  345.             }
  346.             if (world->num_TOBJ+depth > world->num_DESC) {  /* Up a level */
  347.                 depth--;
  348.                 world->curobj=world->curobj->parent;
  349.             }
  350.         } else {
  351.             if (verbose_flag) output_warning(world, "OBJ ", name, size);
  352.             else {
  353.                 for (i=size; i--; ) fgetc(world->inp);    /* Skip this section */
  354.             }
  355.         }
  356.         if (size&1) { fgetc(world->inp); len--; }    /* Skip odd byte */
  357.         len -= size;
  358.     }
  359. }
  360.  
  361. OBJECT *load_external_object(filename, mtrx)
  362. char *filename;
  363. MTRX *mtrx;
  364. {
  365.     WORLD *new;
  366.     FILE *newinp;
  367.     register OBJECT *p;
  368.  
  369.     /* Now, load in the external object */
  370. TRY_EXTR_AGAIN:
  371.     if (!(newinp=fopen(filename, "r"))) {
  372.         fprintf(stderr, "Can't load in EXTR object: '%s'.\n",
  373.             filename);
  374.         fprintf(stderr, "Enter filneame (or CR to abort): "); fflush(stderr);
  375.         fgets(filename, 512, stdin);
  376.         if (!filename[0] || filename[0]=='\n') return(0L);
  377.         goto TRY_EXTR_AGAIN;
  378.     }
  379.     new = read_World(newinp);
  380.     fclose(newinp);
  381.     /* scale, rotate, and translate new object hierarchy */
  382.     for (p=new->object; p; p=p->next)
  383.         move_extr(p, mtrx);
  384.  
  385.     p = new->object;
  386.     free((char*)new);
  387.     return(p);
  388. }
  389.  
  390. static OBJECT *process_EXTR(len, obj, world)
  391. register ULONG len;
  392. OBJECT *obj;
  393. WORLD *world;
  394. {
  395.     register ULONG i, size;
  396.     register EXTR *extr;
  397.     char name[5];
  398.     MTRX *mtrx;
  399.  
  400.     if (!(extr = obj->extr = (EXTR*)malloc(sizeof(EXTR))))
  401.         { OUT_MEM("EXTR"); }
  402.     bzero((char*)extr, sizeof(EXTR));
  403.     mtrx = &extr->mtrx;
  404.     /* Initialize structure */
  405.     mtrx->tran.x  = mtrx->tran.y  = mtrx->tran.z  = 0.0;
  406.     mtrx->scal.x  = mtrx->scal.y  = mtrx->scal.z  = 1.0;
  407.     mtrx->rota1.y = mtrx->rota1.z = 0.0;
  408.     mtrx->rota2.x = mtrx->rota2.z = 0.0;
  409.     mtrx->rota3.x = mtrx->rota3.y = 0.0;
  410.     mtrx->rota1.x = mtrx->rota2.y = mtrx->rota3.z = 1.0;
  411.  
  412.     if (verbose_flag>1) fprintf(stderr, "EXTR chunk.\n");
  413.     while (len>0) {
  414.         get_name(name, 4, world);
  415.         size = get_ULONG(world);
  416.         len -= 8;
  417.         if (verbose_flag>1) fprintf(stderr, "%s chunk.\n", name);
  418.         if (strcmp(name, "MTRX")==0) {
  419.             stuff_XYZ(&mtrx->tran, world);
  420.             stuff_XYZ(&mtrx->scal, world);
  421.             stuff_XYZ(&mtrx->rota1, world);
  422.             stuff_XYZ(&mtrx->rota2, world);
  423.             stuff_XYZ(&mtrx->rota3, world);
  424.         } else
  425.         if (strcmp(name, "LOAD")==0) {
  426.             get_name(extr->filename, 80, world);
  427.         } else {
  428.             if (verbose_flag) output_warning(world, "EXTR ", name, size);
  429.             else {
  430.                 for (i=size; i--; ) fgetc(world->inp);    /* Skip this section */
  431.             }
  432.         }
  433.         if (size&1) { fgetc(world->inp); len--; }    /* Skip odd byte */
  434.         len -= size;
  435.     }
  436.  
  437.     /* Free up unused memory */
  438.     free((char*)obj->extr);
  439.     free((char*)obj);
  440.  
  441.     obj = load_external_object(extr->filename, mtrx);
  442.     return(obj);
  443. }
  444.  
  445. static UBYTE defclst[3], defrlst[3], deftlst[3], defspc1[3];
  446.  
  447. static void malloc_arrays(i, desc)
  448. register int i;
  449. register DESC *desc;
  450. {
  451.     if (!desc->fcount) {
  452.         desc->fcount = i;
  453. if (!(desc->face=(UWORD*)malloc(3*desc->fcount*sizeof(UWORD))))OUT_MEM((char*)0);
  454. if (!(desc->clst=(UBYTE*)malloc(3*desc->fcount*sizeof(UBYTE))))OUT_MEM((char*)0);
  455. if (!(desc->rlst=(UBYTE*)malloc(3*desc->fcount*sizeof(UBYTE))))OUT_MEM((char*)0);
  456. if (!(desc->tlst=(UBYTE*)malloc(3*desc->fcount*sizeof(UBYTE))))OUT_MEM((char*)0);
  457.         /* Initialize arrays */
  458.         for (i=0; i<3*desc->fcount; i+=3) {
  459.             desc->face[i]   = desc->face[i+1] = desc->face[i+2] = 0;
  460.             desc->clst[i]   = defclst[0];
  461.             desc->clst[i+1] = defclst[1];
  462.             desc->clst[i+2] = defclst[2];
  463.             desc->rlst[i]   = defrlst[0];
  464.             desc->rlst[i+1] = defrlst[1];
  465.             desc->rlst[i+2] = defrlst[2];
  466.             desc->tlst[i]   = deftlst[0];
  467.             desc->tlst[i+1] = deftlst[1];
  468.             desc->tlst[i+2] = deftlst[2];
  469.         }
  470.     } else if (i != desc->fcount) {
  471.         fprintf(stderr, "ERROR: FACE and [C|R|T]LST 'Count' values inconsistant.\n");
  472.         OUT_MEM((char*)0);
  473.     }
  474. }
  475.  
  476. static void process_DESC(len, orig, world)
  477. register ULONG len;
  478. DESC **orig;
  479. WORLD *world;
  480. {
  481.     register ULONG size;
  482.     register DESC *desc;
  483.     register int i, j;
  484.     FGRP *fgrp;
  485.     char name[5];
  486.     ULONG ccsize;
  487.  
  488.     if (!(desc = *orig = (DESC*)malloc(sizeof(DESC))))
  489.         { OUT_MEM("DESC"); }
  490.     bzero((char*)desc, sizeof(DESC));
  491.  
  492.     /* Set up defaults: */
  493.     defclst[0] = defclst[1] = defclst[2] = 240; /* TS default */
  494.     defrlst[0] = defrlst[1] = defrlst[2] = 0;
  495.     deftlst[0] = deftlst[1] = deftlst[2] = 0;
  496.     defspc1[0] = defspc1[1] = defspc1[2] = 0;
  497.  
  498.     world->num_DESC++;
  499.  
  500.     if (verbose_flag>1) fprintf(stderr, "DESC chunk.\n");
  501.     while (len>0) {
  502.         get_name(name, 4, world);
  503.         size = get_ULONG(world);
  504.         len -= 8;
  505.         if (verbose_flag>1) fprintf(stderr, "%s chunk.\n", name);
  506.         if (strcmp(name, "NAME")==0) {
  507.             get_name(desc->name, 18, world);
  508.         } else
  509.         if (strcmp(name, "SHAP")==0) {
  510.             if (!desc->shap) {
  511.                 if (!(desc->shap=(WORD*)malloc(2*sizeof(WORD))))
  512.                     { OUT_MEM("SHAP"); }
  513.                 desc->shap[0] = 2;  /* TS defaults */
  514.                 desc->shap[1] = 0;
  515.             }
  516.             desc->shap[0] = get_UWORD(world);
  517.             desc->shap[1] = get_UWORD(world);
  518.         } else
  519.         if (strcmp(name, "POSI")==0) {
  520.             if (!desc->posi) {
  521.                 if (!(desc->posi=(XYZ_st*)malloc(sizeof(XYZ_st))))
  522.                     { OUT_MEM("POSI"); }
  523.             }
  524.             stuff_XYZ(desc->posi, world);
  525.         } else
  526.         if (strcmp(name, "AXIS")==0) {
  527.             if (!desc->axis) {
  528.                 if (!(desc->axis=(AXIS*)malloc(sizeof(AXIS))))
  529.                     { OUT_MEM("AXIS"); }
  530.                 bzero((char*)desc->axis, sizeof(AXIS));
  531.                 desc->axis->xaxi.x = 1;
  532.                 desc->axis->yaxi.y = 1;
  533.                 desc->axis->zaxi.z = 1;
  534.             }
  535.             stuff_XYZ(&desc->axis->xaxi, world);
  536.             stuff_XYZ(&desc->axis->yaxi, world);
  537.             stuff_XYZ(&desc->axis->zaxi, world);
  538.         } else
  539.         if (strcmp(name, "SIZE")==0) {
  540.             if (!desc->size) {
  541.                 if (!(desc->size=(XYZ_st*)malloc(sizeof(XYZ_st))))
  542.                     { OUT_MEM("SIZE"); }
  543.             }
  544.             stuff_XYZ(desc->size, world);
  545.         } else
  546.         if (strcmp(name, "PNTS")==0) {
  547.             i = desc->pcount = get_UWORD(world);    /* Number of points */
  548.             if (!(desc->pnts = (XYZ_st*)malloc(desc->pcount*sizeof(XYZ_st))))
  549.                 OUT_MEM("PNTS");
  550.             for (j=0; j<i; j++)
  551.                 { stuff_XYZ(&desc->pnts[j], world); }
  552.         } else
  553.         if (strcmp(name, "EDGE")==0) {
  554.             i = desc->ecount = get_UWORD(world);    /* Number of edges */
  555.             if (!(desc->edge = (UWORD*)malloc(2*desc->ecount*sizeof(UWORD))))
  556.                 OUT_MEM("EDGE");
  557.             for (j=0; j<2*i; j++)
  558.                 { desc->edge[j] = get_UWORD(world); }
  559.         } else
  560.         if (strcmp(name, "EFLG")==0) {        /* An undocumented chunk */
  561.             if (!(desc->eflg = (EFLG*)malloc(sizeof(EFLG))))
  562.                 OUT_MEM("EFLG");
  563.             i = desc->eflg->num = get_UWORD(world);    /* Number of edge flags */
  564.             if (!(desc->eflg->eflg=(UBYTE*)malloc(desc->eflg->num*sizeof(UBYTE))))
  565.                 OUT_MEM("EFLG");
  566.             for (j=0; j<i; j++)
  567.                 { desc->eflg->eflg[j] = get_UBYTE(world); }
  568.         } else
  569.         if (strcmp(name, "FACE")==0) {
  570.             i = get_UWORD(world);                /* Number of faces */
  571.             malloc_arrays(i, desc);
  572.             for (j=0; j<i; j++) {
  573.                 desc->face[3*j]   = get_UWORD(world);
  574.                 desc->face[3*j+1] = get_UWORD(world);
  575.                 desc->face[3*j+2] = get_UWORD(world);
  576.             }
  577.         } else
  578.         if (strcmp(name, "TXT2")==0) {
  579.             for (i=0; i<4 && desc->txt2[i]; i++) ;
  580.             if (i==4) {        /* ERROR! */
  581.                 fprintf(stderr, "WARNING! More than 4 TXT2 chunks!\n");
  582.                 i--;
  583.             }
  584.             if (!(desc->txt2[i] = (TXT2*)malloc(sizeof(TXT2)))) OUT_MEM("TXT2");
  585.             desc->txt2[i]->Flags = get_UWORD(world);
  586.             ccsize = 2;
  587.             stuff_XYZ(&desc->txt2[i]->TAxis.tran, world);
  588.             stuff_XYZ(&desc->txt2[i]->TAxis.rota1, world);
  589.             stuff_XYZ(&desc->txt2[i]->TAxis.rota2, world);
  590.             stuff_XYZ(&desc->txt2[i]->TAxis.rota3, world);
  591.             stuff_XYZ(&desc->txt2[i]->TAxis.scal, world);
  592.             ccsize = ccsize + 60;
  593.             for (j = 0; j < 16; j++) desc->txt2[i]->Params[j] = get_FRACT(world);
  594.             ccsize = ccsize + 64;
  595.             for (j = 0; j < 16; j++) desc->txt2[i]->PFlags[j] = get_UBYTE(world);
  596.             ccsize = ccsize + 16;
  597.             ccsize = ccsize + 17;
  598.             get_name(desc->txt2[i]->SubName, 17, world);
  599.             j = get_UWORD(world);
  600.             ccsize = ccsize + 2 + j;
  601.             desc->txt2[i]->Length = j;
  602.             get_name(desc->txt2[i]->Name, j, world);
  603.             for (j=ccsize; j < size; j++) get_UBYTE(world);
  604.         } else
  605. #if 0
  606.         if (strcmp(name, "FOR2")==0) {        /* Another undocumented chunk */
  607.             newsize = size;
  608.             i = get_UWORD(world);    /* NumC */
  609.             newsize -= 2;
  610.             NumC = i;
  611.             fprintf(stderr, "Encountered 'FOR2' chunk...size=%lu\n  NumC=%u\n", size, i);
  612.             i = get_UWORD(world);    /* NumF */
  613.             newsize -= 2;
  614.             NumF = i;
  615.             fprintf(stderr, "  NumF=%u\n", i);
  616.             i = get_UWORD(world);    /* Flags */
  617.             newsize -= 2;
  618.             fprintf(stderr, "  Flags=%u\n", i);
  619.             i = get_UWORD(world);    /* pad */
  620.             newsize -= 2;
  621.             fprintf(stderr, "  pad=%u\n", i);
  622.             for (j=0; j<9; j++) fprintf(stderr, "  MTRX[%d]=%.12g\n", j, get_FRACT(world));
  623.             newsize -= 36;
  624.             fprintf(stderr, "  ShiftX=%.12g ", get_FRACT(world));
  625.             fprintf(stderr, "ShiftY=%.12g ", get_FRACT(world));
  626.             fprintf(stderr, "ShiftZ=%.12g\n", get_FRACT(world));
  627.             newsize -= 12;
  628.             for (j=0; j<NumC+4*NumF; j++) {
  629.                 fprintf(stderr, "  Point[%d]: X=%.12g ", j, get_FRACT(world));
  630.                 fprintf(stderr, "Y=%.12g ", get_FRACT(world));
  631.                 fprintf(stderr, "Z=%.12g\n", get_FRACT(world));
  632.                 newsize -= 12;
  633.             }
  634.             output_warning(world, "DESC ", "FOR2", newsize);
  635.         } else
  636. #endif
  637.         if (strcmp(name, "FGRP")==0) {        /* Another undocumented chunk */
  638.             if (!(fgrp = (FGRP*)malloc(sizeof(FGRP))))
  639.                 OUT_MEM("FGRP");
  640.             i = fgrp->num = get_UWORD(world);    /* Number of faces in group */
  641.             if (!(fgrp->face = (UWORD*)malloc(i*sizeof(UWORD))))
  642.                 OUT_MEM("FGRP");
  643.             get_name(fgrp->name, 18, world);
  644.             for (j=0; j<i; j++)
  645.                 fgrp->face[j] = get_UWORD(world);
  646.             /* Link this new FGRP into list */
  647.             fgrp->next = desc->fgrp;
  648.             desc->fgrp = fgrp;
  649.         } else
  650.         if (strcmp(name, "COLR")==0) {
  651.             if (!desc->colr) {
  652.                 if (!(desc->colr = (RGB_st*)malloc(sizeof(RGB_st))))
  653.                     { OUT_MEM("COLR"); }
  654.             }
  655.             stuff_RGB((RGB_st*)&defclst[0], world);
  656.             desc->colr->r = defclst[0];
  657.             desc->colr->g = defclst[1];
  658.             desc->colr->b = defclst[2];
  659.         } else
  660.         if (strcmp(name, "REFL")==0) {
  661.             if (!desc->refl) {
  662.                 if (!(desc->refl = (RGB_st*)malloc(sizeof(RGB_st))))
  663.                     { OUT_MEM("REFL"); }
  664.             }
  665.             stuff_RGB((RGB_st*)&defrlst[0], world);
  666.             desc->refl->r = defrlst[0];
  667.             desc->refl->g = defrlst[1];
  668.             desc->refl->b = defrlst[2];
  669.         } else
  670.         if (strcmp(name, "TRAN")==0) {
  671.             if (!desc->tran) {
  672.                 if (!(desc->tran = (RGB_st*)malloc(sizeof(RGB_st))))
  673.                     { OUT_MEM("TRAN"); }
  674.             }
  675.             stuff_RGB((RGB_st*)&deftlst[0], world);
  676.             desc->tran->r = deftlst[0];
  677.             desc->tran->g = deftlst[1];
  678.             desc->tran->b = deftlst[2];
  679.         } else
  680.         if (strcmp(name, "SPC1")==0) {
  681.             if (!desc->spc1) {
  682.                 if (!(desc->spc1 = (RGB_st*)malloc(sizeof(RGB_st))))
  683.                     { OUT_MEM("SPC1"); }
  684.             }
  685.             stuff_RGB((RGB_st*)&defspc1[0], world);
  686.             desc->spc1->r = defspc1[0];
  687.             desc->spc1->g = defspc1[1];
  688.             desc->spc1->b = defspc1[2];
  689.         } else
  690.         if (strcmp(name, "CLST")==0) {
  691.             i = get_UWORD(world);        /* Number of faces */
  692.             malloc_arrays(i, desc);
  693.             for (j=0; j<i; j++) {
  694.                 desc->clst[3*j+0] = get_UBYTE(world);
  695.                 desc->clst[3*j+1] = get_UBYTE(world);
  696.                 desc->clst[3*j+2] = get_UBYTE(world);
  697.             }
  698.         } else
  699.         if (strcmp(name, "RLST")==0) {
  700.             i = get_UWORD(world);        /* Number of faces */
  701.             malloc_arrays(i, desc);
  702.             for (j=0; j<i; j++) {
  703.                 desc->rlst[3*j+0] = get_UBYTE(world);
  704.                 desc->rlst[3*j+1] = get_UBYTE(world);
  705.                 desc->rlst[3*j+2] = get_UBYTE(world);
  706.             }
  707.         } else
  708.         if (strcmp(name, "TLST")==0) {
  709.             i = get_UWORD(world);        /* Number of faces */
  710.             malloc_arrays(i, desc);
  711.             for (j=0; j<i; j++) {
  712.                 desc->tlst[3*j+0] = get_UBYTE(world);
  713.                 desc->tlst[3*j+1] = get_UBYTE(world);
  714.                 desc->tlst[3*j+2] = get_UBYTE(world);
  715.             }
  716.         } else
  717.         if (strcmp(name, "TPAR")==0) {
  718.             if (!desc->tpar) {
  719.                 if (!(desc->tpar=(double*)malloc(16*sizeof(double))))
  720.                     { OUT_MEM("TPAR"); }
  721.                 bzero((char*)desc->tpar, 16*sizeof(double));
  722.             }
  723.             for (i=0; i<16; i++)
  724.                 desc->tpar[i] = get_FRACT(world);
  725.         } else
  726.         if (strcmp(name, "SURF")==0) {
  727.             if (!desc->surf) {
  728.                 if (!(desc->surf=(UBYTE*)malloc(5*sizeof(UBYTE))))
  729.                     { OUT_MEM("SURF"); }
  730.                 bzero((char*)desc->surf, 5*sizeof(UBYTE));
  731.             }
  732.             for (i=0; i<5; i++)
  733.                 desc->surf[i] = get_BYTE(world);
  734.         } else
  735.         if (strcmp(name, "MTTR")==0) {
  736.             if (!desc->mttr) {
  737.                 if (!(desc->mttr=(MTTR*)malloc(sizeof(MTTR))))
  738.                     { OUT_MEM("MTTR"); }
  739.                 bzero((char*)desc->mttr, sizeof(MTTR));
  740.             }
  741.             desc->mttr->type = get_UBYTE(world);
  742.             desc->mttr->indx = (get_UBYTE(world)/100.0)+1.0;
  743.         } else
  744.         if (strcmp(name, "SPEC")==0) {
  745.             if (!desc->spec) {
  746.                 if (!(desc->spec=(UBYTE*)malloc(2*sizeof(UBYTE))))
  747.                     { OUT_MEM("SPEC"); }
  748.                 bzero((char*)desc->spec, 2*sizeof(UBYTE));
  749.             }
  750.             desc->spec[0] = get_UBYTE(world);
  751.             desc->spec[1] = get_UBYTE(world);
  752.         } else
  753.         if (strcmp(name, "PRP0")==0) {
  754.             if (!desc->prp0) {
  755.                 if (!(desc->prp0=(UBYTE*)malloc(6*sizeof(UBYTE))))
  756.                     { OUT_MEM("PRP0"); }
  757.                 bzero((char*)desc->prp0, 6*sizeof(UBYTE));
  758.             }
  759.             for (i=0; i<6; i++)
  760.                 desc->prp0[i] = get_UBYTE(world);
  761.         } else
  762.         if (strcmp(name, "PRP1")==0) {
  763.             if (!desc->prp1) {
  764.                 if (!(desc->prp1=(UBYTE*)malloc(8*sizeof(UBYTE))))
  765.                     { OUT_MEM("PRP1"); }
  766.                 bzero((char*)desc->prp1, 8*sizeof(UBYTE));
  767.             }
  768.             for (i=0; i<8; i++)
  769.                 desc->prp1[i] = get_UBYTE(world);
  770.         } else
  771.         if (strcmp(name, "INTS")==0) {
  772.             if (!desc->ints) {
  773.                 if (!(desc->ints=(double*)malloc(sizeof(double))))
  774.                     { OUT_MEM("INTS"); }
  775.             }
  776.             *desc->ints = get_FRACT(world);
  777.         } else
  778.         if (strcmp(name, "INT1")==0) {
  779.             if (!desc->int1) desc->int1=(XYZ_st*)malloc(sizeof(XYZ_st));
  780.             if (!desc->int1) { OUT_MEM("INT1"); }
  781.             stuff_XYZ(desc->int1, world);
  782.         } else
  783.         if (strcmp(name, "STRY")==0) {
  784.             get_name(desc->stry->path, 18, world);
  785.             stuff_XYZ(&desc->stry->tran, world);
  786.             stuff_XYZ(&desc->stry->rota, world);
  787.             stuff_XYZ(&desc->stry->scal, world);
  788.             desc->stry->info = get_UWORD(world);
  789.         } else {
  790.             if (verbose_flag) output_warning(world, "DESC ", name, size);
  791.             else {
  792.                 for (i=size; i--; ) fgetc(world->inp);    /* Skip this section */
  793.             }
  794.         }
  795.         if (size&1) { fgetc(world->inp); len--; }    /* Skip odd byte */
  796.         len -= size;
  797.     }
  798. }
  799.  
  800. /* readistg.c - read an Imagine Stage file
  801.  *            - written by Glenn M. Lewis - 8/11/92
  802.  */
  803.  
  804. static void process_OSIZ();
  805. static void process_POSN();
  806. static void process_ALGN();
  807. static void process_PALN();
  808. static void process_TALN();
  809. static void process_PTH2();
  810. static void process_GLB2();
  811. static void process_AXIS();
  812. static void process_LITE();
  813. static void process_FILE();
  814. static void process_SOBJ();
  815.  
  816. WORLD *read_ISTG(file)
  817. FILE *file;
  818. {
  819.     register ULONG i, len, size;
  820.     WORLD *world;
  821.     char name[5];
  822.  
  823.     if (!file) return(0L);    /* File not open */
  824.  
  825.     if (!(world = (WORLD*)malloc(sizeof(WORLD)))) { OUT_MEM("WORLD"); }
  826.     bzero((char*)world, sizeof(WORLD));
  827.     world->inp = file;
  828.  
  829.     if (!already_read_header) {
  830.         /* Parse the IFF ISTG file */
  831.         get_name(name, 4, world);
  832.         if (strcmp(name, "FORM") != 0) {
  833.             fprintf(stderr, "ERROR: Input is not an IFF file.\n"); exit(-1); }
  834.         if (!(len = get_ULONG(world))) {
  835.             fprintf(stderr, "ERROR: Bad FORM length in IFF file.\n"); exit(-1); }
  836.         get_name(name, 4, world);
  837.         if (strcmp(name, "ISTG") != 0) {
  838.             fprintf(stderr, "ERROR: IFF file is not a ISTG file.\n"); exit(-1); }
  839.     } else {
  840.         len =    (header_storage[4]<<24) | (header_storage[5]<<16) |
  841.                 (header_storage[6]<< 8) | (header_storage[7]    );
  842.         already_read_header = 0;
  843.     }
  844.     len -= 4;
  845.  
  846.     /* Allocate the ISTG structure */
  847.     if (!(world->istg = (ISTG*)malloc(sizeof(ISTG)))) { OUT_MEM("ISTG"); }
  848.     bzero((char*)world->istg, sizeof(ISTG));
  849.  
  850. /* Here is the main loop: */
  851.     while (len>0) {
  852.         get_name(name, 4, world);
  853.         size = get_ULONG(world);
  854.         len -= 8;
  855.         if (strcmp(name, "MAXF")==0) world->istg->maxf = get_UWORD(world);
  856.         else
  857.         if (strcmp(name, "SOBJ")==0) process_SOBJ(size, world);
  858.         else {
  859.             if (verbose_flag) output_warning(world, "ISTG ", name, size);
  860.             else {
  861.                 for (i=size; i--; ) fgetc(world->inp);    /* Skip this section */
  862.             }
  863.         }
  864.         if (size&1) { fgetc(world->inp); len--; }    /* Skip odd byte */
  865.         len -= size;
  866.     }
  867.  
  868. /* All done. */
  869.     return(world);
  870. }
  871.  
  872. SOBJ *add_SOBJ(istg)    /* to tail of ISTG's SOBJ list */
  873. ISTG *istg;
  874. {
  875.     SOBJ *new;
  876.  
  877.     if (!(new = (SOBJ*)malloc(sizeof(SOBJ)))) OUT_MEM("SOBJ");
  878.     bzero((char*)new, sizeof(SOBJ));
  879.  
  880.     if (!istg->head) {
  881.         istg->head = istg->tail = new;
  882.         return(new);
  883.     }
  884.     /* Add this SOBJ to the tail */
  885.     new->prev = istg->tail;
  886.     istg->tail->next = new;
  887.     istg->tail = new;
  888.     return(new);
  889. }
  890.  
  891. static void process_SOBJ(len, world)
  892. register ULONG len;
  893. WORLD *world;
  894. {
  895.     register ULONG i, size;
  896.     char name[5];
  897.     SOBJ *sobj;
  898.  
  899.     if (verbose_flag>1) fprintf(stderr, "SOBJ chunk.\n");
  900.     /* Add another SOBJ to the current ISTG list */
  901.     sobj = add_SOBJ(world->istg);
  902.     while (len>0) {
  903.         get_name(name, 4, world);
  904.         size = get_ULONG(world);
  905.         len -= 8;
  906.         if (verbose_flag>1) fprintf(stderr, "%s chunk.\n", name);
  907.         if (strcmp(name, "NAME")==0) { get_name(sobj->name, (int)size, world);
  908.         } else if (strcmp(name, "STGF")==0) { sobj->stgf = get_UWORD(world);
  909.         } else if (strcmp(name, "OSIZ")==0) { process_OSIZ(size, sobj, world);
  910.         } else if (strcmp(name, "POSN")==0) { process_POSN(size, sobj, world);
  911.         } else if (strcmp(name, "ALGN")==0) { process_ALGN(size, sobj, world);
  912.         } else if (strcmp(name, "PALN")==0) { process_PALN(size, sobj, world);
  913.         } else if (strcmp(name, "TALN")==0) { process_TALN(size, sobj, world);
  914.         } else if (strcmp(name, "PTH2")==0) { process_PTH2(size, sobj, world);
  915.         } else if (strcmp(name, "GLB2")==0) { process_GLB2(size, sobj, world);
  916.         } else if (strcmp(name, "AXIS")==0) { process_AXIS(size, sobj, world);
  917.         } else if (strcmp(name, "LITE")==0) { process_LITE(size, sobj, world);
  918.         } else if (strcmp(name, "FILE")==0) { process_FILE(size, sobj, world);
  919.         } else {
  920.             if (verbose_flag) output_warning(world, "SOBJ ", name, size);
  921.             else {
  922.                 for (i=size; i--; ) fgetc(world->inp);    /* Skip this section */
  923.             }
  924.         }
  925.         if (size&1) { fgetc(world->inp); len--; }    /* Skip odd byte */
  926.         len -= size;
  927.     }
  928. }
  929.  
  930. static void process_OSIZ(size, sobj, world)
  931. ULONG size;
  932. SOBJ *sobj;
  933. WORLD *world;
  934. {
  935.     register OSIZ *osiz;
  936.  
  937.     if (!(osiz = (OSIZ*)malloc(sizeof(OSIZ)))) OUT_MEM("OSIZ");
  938.     bzero((char*)osiz, sizeof(OSIZ));
  939.     osiz->flags = get_UWORD(world);
  940.     osiz->start = get_UWORD(world);
  941.     osiz->stop  = get_UWORD(world);
  942.     stuff_XYZ(&osiz->size, world);
  943.     insert_into_sorted_list((PALN**)&sobj->osiz, (PALN*)osiz);
  944. }
  945.  
  946. static void process_POSN(size, sobj, world)
  947. ULONG size;
  948. SOBJ *sobj;
  949. WORLD *world;
  950. {
  951.     register POSN *posn;
  952.  
  953.     if (!(posn = (POSN*)malloc(sizeof(POSN)))) OUT_MEM("POSN");
  954.     bzero((char*)posn, sizeof(POSN));
  955.     posn->flags = get_UWORD(world);
  956.     posn->start = get_UWORD(world);
  957.     posn->stop  = get_UWORD(world);
  958.     stuff_XYZ(&posn->posn, world);
  959.     insert_into_sorted_list((PALN**)&sobj->posn, (PALN*)posn);
  960. }
  961.  
  962. static void process_ALGN(size, sobj, world)
  963. ULONG size;
  964. SOBJ *sobj;
  965. WORLD *world;
  966. {
  967.     register ALGN *algn;
  968.  
  969.     if (!(algn = (ALGN*)malloc(sizeof(ALGN)))) OUT_MEM("ALGN");
  970.     bzero((char*)algn, sizeof(ALGN));
  971.     algn->flags = get_UWORD(world);
  972.     algn->start = get_UWORD(world);
  973.     algn->stop  = get_UWORD(world);
  974.     stuff_XYZ(&algn->algn, world);
  975.     insert_into_sorted_list((PALN**)&sobj->algn, (PALN*)algn);
  976. }
  977.  
  978. static void process_PALN(size, sobj, world)
  979. ULONG size;
  980. SOBJ *sobj;
  981. WORLD *world;
  982. {
  983.     register PALN *paln;
  984.  
  985.     if (!(paln = (PALN*)malloc(sizeof(PALN)))) OUT_MEM("PALN");
  986.     bzero((char*)paln, sizeof(PALN));
  987.     paln->flags = get_UWORD(world);
  988.     paln->start = get_UWORD(world);
  989.     paln->stop  = get_UWORD(world);
  990.     insert_into_sorted_list(&sobj->paln, paln);
  991. }
  992.  
  993. static void process_TALN(size, sobj, world)
  994. ULONG size;
  995. SOBJ *sobj;
  996. WORLD *world;
  997. {
  998.     register TALN *taln;
  999.  
  1000.     if (!(taln = (TALN*)malloc(sizeof(TALN)))) OUT_MEM("TALN");
  1001.     bzero((char*)taln, sizeof(TALN));
  1002.     taln->flags = get_UWORD(world);
  1003.     taln->start = get_UWORD(world);
  1004.     taln->stop  = get_UWORD(world);
  1005.     taln->initial_y = get_FRACT(world);
  1006.     taln->final_y   = get_FRACT(world);
  1007.     size -= 15L;
  1008.     /* BCPL string... byte followed by string, followed by zero */
  1009.     get_UBYTE(world);
  1010.     if (size)
  1011.         get_name(taln->trackobj, (int)size, world);
  1012.     insert_into_sorted_list((PALN**)&sobj->taln, (PALN*)taln);
  1013. }
  1014.  
  1015. static void process_PTH2(size, sobj, world)
  1016. ULONG size;
  1017. SOBJ *sobj;
  1018. WORLD *world;
  1019. {
  1020.     register PTH2 *pth2;
  1021.  
  1022.     if (!(pth2 = (PTH2*)malloc(sizeof(PTH2)))) OUT_MEM("PTH2");
  1023.     bzero((char*)pth2, sizeof(PTH2));
  1024.     pth2->flags = get_UWORD(world);
  1025.     pth2->start = get_UWORD(world);
  1026.     pth2->stop  = get_UWORD(world);
  1027.     pth2->acceleration_frames = get_ULONG(world);
  1028.     pth2->start_speed = get_FRACT(world);
  1029.     pth2->deacceleration_frames = get_ULONG(world);
  1030.     pth2->end_speed = get_FRACT(world);
  1031.     size -= 23L;
  1032.     /* BCPL string... byte followed by string, followed by zero */
  1033.     get_UBYTE(world);
  1034.     if (size)
  1035.         get_name(pth2->path, (int)size, world);
  1036.     insert_into_sorted_list((PALN**)&sobj->pth2, (PALN*)pth2);
  1037. }
  1038.  
  1039. static void process_GLB2(size, sobj, world)
  1040. ULONG size;
  1041. SOBJ *sobj;
  1042. WORLD *world;
  1043. {
  1044.     register GLB2 *glb2;
  1045.  
  1046.     if (!(glb2 = (GLB2*)malloc(sizeof(GLB2)))) OUT_MEM("GLB2");
  1047.     bzero((char*)glb2, sizeof(GLB2));
  1048.     glb2->flags = get_UWORD(world);
  1049.     glb2->start = get_UWORD(world);
  1050.     glb2->stop  = get_UWORD(world);
  1051.     glb2->sky_blending = get_ULONG(world);
  1052.     glb2->starfield = get_FRACT(world);
  1053.     glb2->transition = get_ULONG(world);
  1054.     /* The following are FRACTional colors */
  1055.     stuff_XYZ(&glb2->ambient, world);
  1056.     stuff_XYZ(&glb2->horizon, world);
  1057.     stuff_XYZ(&glb2->zenith1, world);
  1058.     stuff_XYZ(&glb2->zenith2, world);
  1059.     stuff_XYZ(&glb2->fog_color, world);
  1060.     glb2->fog_bottom = get_FRACT(world);
  1061.     glb2->fog_top    = get_FRACT(world);
  1062.     glb2->fog_length = get_FRACT(world);
  1063.     glb2->brush_seq  = get_ULONG(world);
  1064.     glb2->backdrop_seq = get_ULONG(world);
  1065.     get_name(glb2->backdrop, 256, world);        /* Fixed size */
  1066.     size -= 355L;
  1067.     /* BCPL string... byte followed by string, followed by zero */
  1068.     get_UBYTE(world);
  1069.     if (size)
  1070.         get_name(glb2->globalbrush, (int)size, world);    /* Var. size */
  1071.     insert_into_sorted_list((PALN**)&sobj->glb2, (PALN*)glb2);
  1072. }
  1073.  
  1074. static void process_AXIS(size, sobj, world)
  1075. ULONG size;
  1076. SOBJ *sobj;
  1077. WORLD *world;
  1078. {
  1079.     register SAXIS *axis;
  1080.  
  1081.     if (!(axis = (SAXIS*)malloc(sizeof(SAXIS)))) OUT_MEM("SAXIS");
  1082.     bzero((char*)axis, sizeof(SAXIS));
  1083.     axis->flags = get_UWORD(world);
  1084.     axis->start = get_UWORD(world);
  1085.     axis->stop  = get_UWORD(world);
  1086.     insert_into_sorted_list((PALN**)&sobj->axis, (PALN*)axis);
  1087. }
  1088.  
  1089. static void process_LITE(size, sobj, world)
  1090. ULONG size;
  1091. SOBJ *sobj;
  1092. WORLD *world;
  1093. {
  1094.     register LITE *lite;
  1095.  
  1096.     if (!(lite = (LITE*)malloc(sizeof(LITE)))) OUT_MEM("LITE");
  1097.     bzero((char*)lite, sizeof(LITE));
  1098.     lite->flags = get_UWORD(world);
  1099.     lite->start = get_UWORD(world);
  1100.     lite->stop  = get_UWORD(world);
  1101.     /* The following is a FRACTional color */
  1102.     stuff_XYZ(&lite->color, world);
  1103.     lite->transition = get_ULONG(world);
  1104.     insert_into_sorted_list((PALN**)&sobj->lite, (PALN*)lite);
  1105. }
  1106.  
  1107. static void process_FILE(size, sobj, world)
  1108. ULONG size;
  1109. SOBJ *sobj;
  1110. WORLD *world;
  1111. {
  1112.     register SFILE *file;
  1113.  
  1114.     if (!(file = (SFILE*)malloc(sizeof(SFILE)))) OUT_MEM("SFILE");
  1115.     bzero((char*)file, sizeof(SFILE));
  1116.     file->flags = get_UWORD(world);
  1117.     file->start = get_UWORD(world);
  1118.     file->stop  = get_UWORD(world);
  1119.     file->cycles_to_perform = get_FRACT(world);
  1120.     file->initial_cycle_phase = get_FRACT(world);
  1121.     file->transition = get_ULONG(world);
  1122.     size -= 19L;
  1123.     /* BCPL string... byte followed by string, followed by zero */
  1124.     get_UBYTE(world);
  1125.     if (size)
  1126.         get_name(file->object_description, (int)size, world);
  1127.     insert_into_sorted_list((PALN**)&sobj->file, (PALN*)file);
  1128. }
  1129.  
  1130. /* We use "PALN" here, even though this routine inserts all SOBJ sub-types
  1131.  * into their proper list, because all be need is "START" and "STOP"
  1132.  * information, and "PALN" is the minimal structure that provides this
  1133.  */
  1134. void insert_into_sorted_list(ppaln, paln)
  1135. PALN **ppaln, *paln;
  1136. {
  1137.     register PALN *p;
  1138.  
  1139.     if (!*ppaln) { *ppaln = paln; return; }        /* First in list */
  1140.     /* Now search through the list and insert in the proper place */
  1141.     for (p= *ppaln; p; p=p->next) {
  1142.         if (paln->start == p->start ||
  1143.             paln->start == p->stop  ||
  1144.             paln->stop  == p->start ||
  1145.             paln->stop  == p->stop) {
  1146.             fprintf(stderr, "WARNING!!! start and stop times collide! (%u-%u) vs (%u-%u)\n",
  1147.                 paln->start, paln->stop, p->start, p->stop);
  1148.         }
  1149.         if (paln->stop < p->start) {    /* Insert the item before this one */
  1150.             paln->prev = p->prev;
  1151.             paln->next = p;
  1152.             p->prev = paln;
  1153.             if (p == *ppaln) { *ppaln = paln; }    /* New head of list */
  1154.             return;
  1155.         }
  1156.         if (!p->next) {    /* Insert after this item */
  1157.             p->next = paln;
  1158.             paln->prev = p;
  1159.             return;
  1160.         }
  1161.     }
  1162.     /* Never will reach here! */
  1163. }
  1164.  
  1165. /* Find the last existing key frame that would be applicable for "frame" */
  1166. void delete_unused_frames(orig, frame)
  1167. PALN **orig;
  1168. {
  1169.     register PALN *p;
  1170.     PALN *p2;
  1171.  
  1172.     for (p= *orig; p; ) {
  1173.         if (frame>=p->start && frame<=p->stop) return;        /* It falls within this keyframe */
  1174.         if (frame>=p->stop && (!p->next || (p->next && frame<p->next->start))) return;        /* This is the one! */
  1175.         /* Otherwise, delete it */
  1176.         if (p->next) p->next->prev = p->prev;
  1177.         if (p->prev) p->prev->next = p->next;
  1178.         if (p== *orig) *orig = p->next;
  1179.         p2 = p->next;
  1180.         free(p);
  1181.         p = p2;
  1182.     }
  1183. }
  1184.  
  1185. static void mtrx_ident(mtrx)
  1186. register MTRX *mtrx;
  1187. {
  1188.     mtrx->tran.x  = mtrx->tran.y  = mtrx->tran.z  = 0.0;
  1189.     mtrx->scal.x  = mtrx->scal.y  = mtrx->scal.z  = 1.0;
  1190.     mtrx->rota1.y = mtrx->rota1.z = 0.0;
  1191.     mtrx->rota2.x = mtrx->rota2.z = 0.0;
  1192.     mtrx->rota3.x = mtrx->rota3.y = 0.0;
  1193.     mtrx->rota1.x = mtrx->rota2.y = mtrx->rota3.z = 1.0;
  1194. }
  1195.  
  1196. static void mmultiply(s, d)
  1197. register double *s;
  1198. register double *d;
  1199. {
  1200.     register int j;
  1201.     double tmp[9];
  1202.     tmp[0] = s[0]*d[0] + s[1]*d[3] + s[2]*d[6];
  1203.     tmp[1] = s[0]*d[1] + s[1]*d[4] + s[2]*d[7];
  1204.     tmp[2] = s[0]*d[2] + s[1]*d[5] + s[2]*d[8];
  1205.     tmp[3] = s[3]*d[0] + s[4]*d[3] + s[5]*d[6];
  1206.     tmp[4] = s[3]*d[1] + s[4]*d[4] + s[5]*d[7];
  1207.     tmp[5] = s[3]*d[2] + s[4]*d[5] + s[5]*d[8];
  1208.     tmp[6] = s[6]*d[0] + s[7]*d[3] + s[8]*d[6];
  1209.     tmp[7] = s[6]*d[1] + s[7]*d[4] + s[8]*d[7];
  1210.     tmp[8] = s[6]*d[2] + s[7]*d[5] + s[8]*d[8];
  1211.     for (j = 9; j--; ) d[j] = tmp[j];
  1212. }
  1213.  
  1214. /*
  1215. Matrix Inversion
  1216. by Richard Carling
  1217. from "Graphics Gems", Academic Press, 1990
  1218. tweaked heavily by Glenn M. Lewis to not require "GraphicsGems.h" and
  1219. to work only on 3x3 matrices
  1220. */
  1221.  
  1222.  
  1223. #define SMALL_NUMBER    1.e-8
  1224. #define det2x2(a,b,c,d)    ((a)*(d)-(b)*(c))
  1225. #define det3x3(a1, a2, a3, b1, b2, b3, c1, c2, c3)    \
  1226.     ((a1) * det2x2((b2), (b3), (c2), (c3))    \
  1227.     -(b1) * det2x2((a2), (a3), (c2), (c3))    \
  1228.     +(c1) * det2x2((a2), (a3), (b2), (b3)))
  1229.  
  1230. /* 
  1231.  *   inverse(original_matrix, inverse_matrix)
  1232.  * 
  1233.  *    calculate the inverse of a 3x3 matrix
  1234.  *
  1235.  *     -1     
  1236.  *     A  = ___1__ adjoint A
  1237.  *         det A
  1238.  */
  1239.  
  1240. void inverse(in, out)
  1241. register double *in, *out;
  1242. {
  1243.     int i;
  1244.     double det;
  1245.     void adjoint();
  1246.  
  1247.     /* calculate the adjoint matrix */
  1248.     adjoint(in, out);
  1249.     /*  calculate the 3x3 determinent
  1250.      *  if the determinent is zero, 
  1251.      *  then the inverse matrix is not unique.
  1252.      */
  1253.     det = det3x3(
  1254.         in[0], in[1], in[2],
  1255.         in[3], in[4], in[5],
  1256.         in[6], in[7], in[8]
  1257.     );
  1258.     if (fabs(det) < SMALL_NUMBER) return;    /* non-singular matrix */
  1259.     /* scale the adjoint matrix to get the inverse */
  1260.     det = 1.0/det;
  1261.     for (i=0; i<9; i++) out[i] *= det;
  1262. }
  1263.  
  1264. /* 
  1265.  *   adjoint(original_matrix, inverse_matrix)
  1266.  * 
  1267.  *     calculate the adjoint of a 4x4 matrix
  1268.  *
  1269.  *      Let  a   denote the minor determinant of matrix A obtained by
  1270.  *           ij
  1271.  *
  1272.  *      deleting the ith row and jth column from A.
  1273.  *
  1274.  *                    i+j
  1275.  *     Let  b   = (-1)    a
  1276.  *          ij            ji
  1277.  *
  1278.  *    The matrix B = (b  ) is the adjoint of A
  1279.  *                     ij
  1280.  */
  1281.  
  1282. void adjoint(in, out)
  1283. register double *in, *out;
  1284. {
  1285.     /* row column labeling reversed since we transpose rows & columns */
  1286.     out[0]  =   det2x2(in[4], in[7], in[5], in[8]);
  1287.     out[4]  = - det2x2(in[3], in[6], in[5], in[8]);
  1288.     out[6]  =   det2x2(in[3], in[6], in[4], in[7]);
  1289.  
  1290.     out[1]  = - det2x2(in[1], in[7], in[2], in[8]);
  1291.     out[4]  =   det2x2(in[0], in[6], in[2], in[8]);
  1292.     out[7]  = - det2x2(in[0], in[6], in[1], in[7]);
  1293.  
  1294.     out[2]  =   det2x2(in[1], in[4], in[2], in[5]);
  1295.     out[5]  = - det2x2(in[0], in[3], in[2], in[5]);
  1296.     out[8]  =   det2x2(in[0], in[3], in[1], in[4]);
  1297. }
  1298.  
  1299. OBJECT *load_staging_object(filename, mtrx)
  1300. char *filename;
  1301. MTRX *mtrx;
  1302. {
  1303.     WORLD *new;
  1304.     FILE *newinp;
  1305.     register OBJECT *p;
  1306.  
  1307.     /* Now, load in the external object */
  1308. TRY_EXTR_AGAIN:
  1309.     if (!(newinp=fopen(filename, "r"))) {
  1310.         fprintf(stderr, "Can't load in EXTR object: '%s'.\n",
  1311.             filename);
  1312.         fprintf(stderr, "Enter filneame (or CR to abort): "); fflush(stderr);
  1313.         fgets(filename, 512, stdin);
  1314.         if (!filename[0] || filename[0]=='\n') return(0L);
  1315.         goto TRY_EXTR_AGAIN;
  1316.     }
  1317.     new = read_World(newinp);
  1318.     fclose(newinp);
  1319.  
  1320.     /* scale, rotate, and translate new object hierarchy */
  1321.     /* First, take a look at the root object's size an orientation,
  1322.      * and scale all subobjects appropriately
  1323.      */
  1324.  
  1325.     p = new->object;
  1326.     if (p) {
  1327.         if (p->desc->size) {
  1328.             if (p->desc->size->x != 0.0)
  1329.                 mtrx->scal.x /= p->desc->size->x;
  1330.             if (p->desc->size->y != 0.0)
  1331.                 mtrx->scal.y /= p->desc->size->y;
  1332.             if (p->desc->size->z != 0.0)
  1333.                 mtrx->scal.z /= p->desc->size->z;
  1334.         }
  1335.         if (p->desc->axis) {
  1336. /*            inverse(&p->desc->axis->xaxi.x, &newmtrx.rota1.x);    */
  1337. /*            mmultiply(&newmtrx.rota1.x, &mtrx->rota1.x);            */
  1338.             mmultiply(&p->desc->axis->xaxi.x, &mtrx->rota1.x);
  1339.         }
  1340.     }
  1341.     for (p=new->object; p; p=p->next)
  1342.         move_extr(p, mtrx);
  1343.  
  1344.     p = new->object;
  1345.     free((char*)new);
  1346.     return(p);
  1347. }
  1348.  
  1349. void load_staging_frame_objects(world, frame)
  1350. WORLD *world;
  1351. int frame;
  1352. {
  1353.     register SOBJ *sobj;
  1354.     MTRX mtrx, tmpmtrx;
  1355.     OBJECT *obj;
  1356.     double angle, sin(), cos();
  1357.  
  1358.     if (!world) return;
  1359.     if (!world->istg) return;
  1360.     if (frame<1 || frame>world->istg->maxf) {
  1361.         fprintf(stderr, "ERROR: desired frame (%d) is larger than MAXF (%d)\n",
  1362.             frame, world->istg->maxf);
  1363.         return;
  1364.     }
  1365.     /* Search through all of the "SOBJ" chunks and load in objects that
  1366.      * are active during the specified frame
  1367.      */
  1368.     for (sobj=world->istg->head; sobj; sobj=sobj->next) {
  1369.         /* Easiest method is to simply delete all the information in the SOBJ
  1370.          * sub-chunks that does not fall within the specified frame time.
  1371.          */
  1372.         delete_unused_frames((PALN**)&sobj->osiz, frame);        /* Size */
  1373.         delete_unused_frames((PALN**)&sobj->posn, frame);        /* Position */
  1374.         delete_unused_frames((PALN**)&sobj->algn, frame);        /* Alignment */
  1375.         delete_unused_frames((PALN**)&sobj->paln, frame);        /* Path Alignment */
  1376.         delete_unused_frames((PALN**)&sobj->taln, frame);        /* Track Alignment */
  1377.         delete_unused_frames((PALN**)&sobj->pth2, frame);        /* Follow Path */
  1378.         delete_unused_frames((PALN**)&sobj->glb2, frame);        /* Globals */
  1379.         delete_unused_frames((PALN**)&sobj->axis, frame);        /* Stagefile AXIS */
  1380.         delete_unused_frames((PALN**)&sobj->lite, frame);        /* Light */
  1381.         delete_unused_frames((PALN**)&sobj->file, frame);        /* Stage file */
  1382.  
  1383.         /* Now, we have a list of SOBJ chunks with information for this frame */
  1384.         if (!sobj->file) continue;    /* No filename information */
  1385.  
  1386.         /* Initialize transformation matrix structure */
  1387.         mtrx_ident(&mtrx);
  1388.  
  1389.         /* Now modify matrix based upon requested transformations */
  1390.         if (sobj->posn) { bcopy((char*)&sobj->posn->posn.x, (char*)&mtrx.tran.x, sizeof(XYZ_st)); }
  1391.         if (sobj->osiz) { bcopy((char*)&sobj->osiz->size.x, (char*)&mtrx.scal.x, sizeof(XYZ_st)); }
  1392.         if (sobj->algn) {
  1393.             /* First Z rotation, then X, then Y */
  1394.             if (sobj->algn->algn.z != 0.0) {
  1395.                 angle = sobj->algn->algn.z * PI / 180.0;
  1396.                 mtrx_ident(&tmpmtrx);    /* Initialize it */
  1397.                 tmpmtrx.rota1.x = tmpmtrx.rota2.y = cos(angle);
  1398.                 tmpmtrx.rota2.x = sin(angle);
  1399.                 tmpmtrx.rota1.y = -tmpmtrx.rota2.x;
  1400.                 mmultiply(&tmpmtrx.rota1.x, &mtrx.rota1.x);
  1401.             } else if (sobj->algn->algn.x != 0.0) {
  1402.                 angle = sobj->algn->algn.x * PI / 180.0;
  1403.                 mtrx_ident(&tmpmtrx);    /* Initialize it */
  1404.                 tmpmtrx.rota2.y = tmpmtrx.rota3.z = cos(angle);
  1405.                 tmpmtrx.rota3.y = sin(angle);
  1406.                 tmpmtrx.rota2.z = -tmpmtrx.rota3.y;
  1407.                 mmultiply(&tmpmtrx.rota1.x, &mtrx.rota1.x);
  1408.             } else if (sobj->algn->algn.y != 0.0) {
  1409.                 angle = sobj->algn->algn.y * PI / 180.0;
  1410.                 mtrx_ident(&tmpmtrx);    /* Initialize it */
  1411.                 tmpmtrx.rota1.x = tmpmtrx.rota3.z = cos(angle);
  1412.                 tmpmtrx.rota1.z = sin(angle);
  1413.                 tmpmtrx.rota3.x = -tmpmtrx.rota1.z;
  1414.                 mmultiply(&tmpmtrx.rota1.x, &mtrx.rota1.x);
  1415.             }
  1416.         }
  1417.         /* Okeydokey... let's load in that object! */
  1418.         obj = load_staging_object(sobj->file->object_description, &mtrx);
  1419.         if (world->curobj) {
  1420.             world->curobj->next = obj;
  1421.             obj->parent = world->curobj->parent;
  1422.             while (obj->next) {
  1423.                 obj->next->parent = obj->parent;
  1424.                 obj = obj->next;
  1425.                 world->curobj = obj;
  1426.             }
  1427.         } else {
  1428.             world->object = obj;
  1429.             obj->parent = 0;
  1430.         }
  1431.         world->curobj = obj;
  1432.     }
  1433. }
  1434.